package drp.snowbell.annotation;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;


import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import drp.snowbell.cfg.Config;
import drp.snowbell.cfg.EntityConfig;
import drp.snowbell.cfg.PartConfig;
import drp.snowbell.cfg.PartParameter;
import drp.snowbell.cfg.PropertyConfig;
import drp.snowbell.cfg.RelationConfig;
import drp.snowbell.entity.Entity;
import drp.snowbell.entity.IEntity;
import drp.snowbell.entity.IPart;
import drp.snowbell.entity.Relation;
import drp.snowbell.exception.CatchException;
import drp.snowbell.util.BaseFieldType;
import drp.snowbell.util.StrHelper;
import drp.snowbell.util.TypeHelper;

public class AnnotationLoader {
	private static Collection<PropertyConfig> baseEntityPropertyConfigList;

	public static EntityConfig buildEntityContig(Class<? extends IEntity> entityClass) {
		EntityConfig config = null;
		if (entityClass != Entity.class) {
			AEntity ann = entityClass.getAnnotation(AEntity.class);
			if (ann != null) {
				config = new EntityConfig();
				String name = ann.name();
				if (StrHelper.isNullOrEmpty(name)) {
					name = entityClass.getName();// 名称为空的话取类名
				}
				config.setName(name);

				config.setClassName(entityClass.getName());
				config.setStorageClass(ann.storage());
				config.setIsCache(ann.isCache());
				String strParts = ann.parts();
				config.setParts(toPartParamList(strParts));
				config.setTableName(ann.table());
				config.setIsGenerated(false);// 肯定不是生成
				config.setConfigDefinitions(ann.configDefinitions());

				Collection<RelationConfig> outRelaConfig = new ArrayList<RelationConfig>();
				Map<String, String> alias = new HashMap<String, String>();
				loadRelation(name, entityClass, outRelaConfig, alias);
				config.setRelations(outRelaConfig);

				Map<String, PropertyConfig> outPorpList = new HashMap<String, PropertyConfig>();
				loadProperty(entityClass, false, alias, outPorpList);
				config.setProperties(outPorpList.values());

			}
		} else {
			// 如果是根实体的话只获取属性列表
			config = new EntityConfig();
			Map<String, String> alias = new HashMap<String, String>();
			Map<String, PropertyConfig> outPorpList = new HashMap<String, PropertyConfig>();
			loadProperty(entityClass, false, alias, outPorpList);
			config.setProperties(outPorpList.values());
		}
		return config;
	}

	public static PartConfig buildPartConfig(Class<? extends IPart> clazz) {
		PartConfig config = null;
		if (clazz.isAnnotationPresent(APart.class)) {
			APart part = clazz.getAnnotation(APart.class);
			if (part != null) {
				config = new PartConfig();
				String name = part.name();
				if (StrHelper.isNullOrEmpty(name)) {
					name = clazz.getName();
				}
				config.setName(name);
				config.setClassName(clazz.getName());
				Map<String, PropertyConfig> outPorpList = new HashMap<String, PropertyConfig>();
				loadProperty(clazz, true, null, outPorpList);

				config.setProperties(outPorpList.values());
			}

		}
		return config;
	}

	public static Collection<PropertyConfig> getBaseEntityPropertyConfigList() {
		if (baseEntityPropertyConfigList == null) {
			Map<String, PropertyConfig> map = new HashMap<String, PropertyConfig>();
			loadProperty(Entity.class, false, null, map);
			baseEntityPropertyConfigList = map.values();
		}
		return baseEntityPropertyConfigList;
	}

	private static void loadProperty(Class<?> clazz, boolean isSkill, Map<String, String> alias, Map<String, PropertyConfig> outPorpMap) {
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			// field.setAccessible(true);
			if (field.isAnnotationPresent(AProperty.class)) {
				// 如果有Property的注释
				String fieldName = field.getName();
				String name = fieldName;
				if (!outPorpMap.containsKey(name)) {
					AProperty prop = field.getAnnotation(AProperty.class);
					Class<?> clazzType = field.getType();
					BaseFieldType fieldType = TypeHelper.getType(clazzType);
					String lable = prop.label();
					if (StrHelper.isNullOrEmpty(lable)) {
						lable = StrHelper.toUpperRule(name);// 如果为空,默认lable
						// 为名称的大写下划线方式
					}
					String dbType = prop.dbType();
					if (StrHelper.isNullOrEmpty(dbType)) {
						dbType = TypeHelper.getDbType(clazzType).name();
					}
					int length = prop.dbLength();
					if (length <= 0 && fieldType == BaseFieldType.String) {
						// 如果是字符串数据 而且没有设置长度,则设置为默认长度
						length = Config.get().getDefaultDbFieldLength();
					}
					String valueType = prop.valueType();
					if (StrHelper.isNullOrEmpty(valueType)) {
						valueType = fieldType.name();
					}
					PropertyConfig pc = new PropertyConfig();
					pc.setDbDefaultValue(prop.dbDefaultValue());
					pc.setDbLength(length);
					pc.setDbType(dbType);
					pc.setLabel(lable);
					pc.setName(name);// 字段的名称
					pc.setIsRequired(prop.isRequired());
					pc.setIsReadOnly(prop.isReadOnly());
					pc.setIsUnique(prop.isUnique());
					pc.setValueType(valueType);
					pc.setFullTextConfig(prop.fullTextConfig());
					// pc.setIsDbField(prop.isDbField());
					String getterName = prop.getter();
					if (getterName.length() == 0) {
						getterName = "get" + name;
					}
					pc.setGetterName(getterName);
					String setterName = prop.setter();
					if (setterName.length() == 0) {
						setterName = "set" + name;
					}
					pc.setSetterName(setterName);
					// 处理关联表达式
					String aliasName = prop.relation();
					if (!StrHelper.isNullOrEmpty(aliasName)) {
						if (alias != null) {
							if (alias.containsKey(aliasName)) {
								// 需要把别名替换为真名
								String relaName = alias.get(aliasName);
								if (relaName != null) {
									pc.setRelation(relaName);
								} else {
									CatchException.error(AnnotationLoader.class, "invalid relation alias");
								}
							}
						}
					}

					if (StrHelper.isNullOrEmpty(pc.getRelation())) {
						// 如果是关联属性
						String dbFieldName = prop.dbFieldName();
						boolean isPersistent = prop.isPersistent();
						pc.setIsPersistent(isPersistent);
						if (isPersistent) {
							if (StrHelper.isNullOrEmpty(dbFieldName)) {
								dbFieldName = name;// 如果为空,数据库字段名称默认等于属性名称
							}
							pc.setDbFieldName(dbFieldName);

						} else {
							dbFieldName = "";
						}
					} else {
						// 如果存在关联的话则数据库字段设置为空
						pc.setDbFieldName("");
						pc.setIsPersistent(false);
					}
					String dbDefaultValue = prop.dbDefaultValue();
					if (StrHelper.isNullOrEmpty(dbDefaultValue)) {
						dbDefaultValue = null;
					}
					pc.setDbDefaultValue(dbDefaultValue);

					outPorpMap.put(name, pc);
				}
			}
		}
	}

	/**
	 * 加载注释关联配置
	 * 
	 * @param clazz
	 * @param outRelaConfig
	 */
	private static void loadRelation(String beanName, Class<? extends IEntity> clazz, Collection<RelationConfig> outRelaConfig,
			Map<String, String> outAlias) {
		if (clazz.isAnnotationPresent(ARelation.class)) {
			ARelation rela = clazz.getAnnotation(ARelation.class);

			String aliasName = rela.alias();
			if (!outAlias.containsKey(aliasName)) {
				String name = Relation.generateRelName(beanName, rela.mProperty(), rela.rBean(), rela.rProperty());
				outAlias.put(aliasName, name);

				RelationConfig rc = new RelationConfig();
				rc.setMFieldName(rela.mField());
				rc.setMProperty(rela.mProperty());
				rc.setRBeanName(rela.rBean());
				rc.setRelationType(rela.relationType().toString());
				rc.setRelTable(rela.rt());
				rc.setRelTableMFieldName(rela.rtMField());
				rc.setRelTableRFieldName(rela.rtRField());
				rc.setRFieldName(rela.rField());
				rc.setRProperty(rela.rProperty());
				rc.setIsPureRelTable(rela.isPureRelTable());
				outRelaConfig.add(rc);
			}
		}
	}

	// TODO 移动到Part的构造函数里
	/**
	 * 把技能字符串的配置转换为List
	 * 
	 * @param strParts
	 *            配置字符串
	 * @return
	 */
	private static Collection<PartParameter> toPartParamList(String strParts) {
		Collection<PartParameter> paramList = new ArrayList<PartParameter>();
		if (!StrHelper.isNullOrEmpty(strParts)) {
			strParts = strParts.trim();
			JsonParser parser = new JsonParser();
			Gson gson = new Gson();
			if (strParts.charAt(0) == '[') {
				// 说明是多个json数据
				JsonArray array = parser.parse(strParts).getAsJsonArray();
				for (JsonElement el : array) {
					PartParameter param = gson.fromJson(el, PartParameter.class);
					paramList.add(param);
				}
			} else if (strParts.charAt(0) == '{') {
				// 单个json数据
				PartParameter param = gson.fromJson(strParts, PartParameter.class);
				paramList.add(param);
			} else {
				// 原始的逗号分割
				String[] array = strParts.split(",");
				for (String partName : array) {
					PartParameter param = new PartParameter();
					int dot = partName.indexOf('.');
					if (dot > 0) {
						param.setModuleName(partName.substring(0, dot));
						param.setPartName(partName.substring(dot + 1));
					} else {
						param.setModuleName(Config.CORE_MODULE_NAME);// 默认系统模块
						param.setPartName(partName);
					}
					param.setParameter(null);
					paramList.add(param);
				}
			}
		}
		return paramList;
	}
}
